﻿Imports System.Collections.Generic
Imports System.ComponentModel
Imports System.Drawing
Imports System.Data
Imports System.Text
Imports System.Windows.Forms
Imports System.Runtime.InteropServices

Partial Public Class ListViewEx
    Inherits ListView
    Const WM_USER As Integer = &H400
    Const WM_NOTIFY As Integer = &H4E
    Const OCM_BASE As Integer = WM_USER + &H1C00
    Const OCM_NOTIFY As Integer = OCM_BASE + WM_NOTIFY
    Const LVN_FIRST As Integer = 0 - 100
    Const LVN_ITEMCHANGING As Integer = LVN_FIRST - 0
    Const LVIF_STATE As Integer = &H8
    Const LVIS_UNSELECTED As Integer = &H0
    Const LVIS_FOCUSED As Integer = &H1
    Const LVIS_SELECTED As Integer = &H2
    Const LVIS_SELECTED_FOCUSED As Integer = &H3

    <StructLayout(LayoutKind.Sequential)> _
    Public Structure NMHDR
        Public hwndFrom As IntPtr
        Public idFrom As Integer
        Public code As Integer
    End Structure
    <StructLayout(LayoutKind.Sequential)> _
    Public Structure POINT
        Public x As Integer
        Public y As Integer
    End Structure
    <StructLayout(LayoutKind.Sequential)> _
    Public Structure NMLISTVIEW
        Public hdr As NMHDR
        Public iItem As Integer
        Public iSubItem As Integer
        Public uNewState As Integer
        Public uOldState As Integer
        Public uChanged As Integer
        Public ptAction As POINT
        Public lParam As Integer
    End Structure
    Public Delegate Sub ItemDeselectingEventHandler(ByVal sender As Object, ByVal e As ItemChangingEventArgs)
    Public Event ItemDeselecting As ItemDeselectingEventHandler
    Private m_cancel As Boolean

    Protected Overridable Sub OnItemDeselecting(ByVal e As ItemChangingEventArgs)
        RaiseEvent ItemDeselecting(Me, e)
    End Sub
    Protected Overrides Sub WndProc(ByRef m As Message)
        If m.Msg = OCM_NOTIFY Then
            Dim nm As NMHDR = CType(m.GetLParam(GetType(NMHDR)), NMHDR)
            If nm.code = LVN_ITEMCHANGING Then
                Dim nmlv As NMLISTVIEW = CType(m.GetLParam(GetType(NMLISTVIEW)), NMLISTVIEW)
                ItemStateChanging(m, nmlv)
            End If
        End If
        MyBase.WndProc(m)
    End Sub
    Private Sub ItemStateChanging(ByRef m As Message, ByRef nmlv As NMLISTVIEW)
        If (nmlv.uChanged And LVIF_STATE) = LVIF_STATE Then
            'FROM ITEM
            If (nmlv.uOldState = LVIS_SELECTED) OrElse (nmlv.uNewState = LVIS_UNSELECTED) Then
                If m_cancel Then
                    m.Result = New IntPtr(1)
                    m_cancel = False
                Else
                    Dim e As New ItemChangingEventArgs(nmlv.iItem, Me.Items(nmlv.iItem))
                    OnItemDeselecting(e)
                    If e.Cancel Then
                        m.Result = New IntPtr(1)
                        m_cancel = True
                    End If
                End If
                'TO ITEM
            ElseIf (nmlv.uOldState = LVIS_UNSELECTED) OrElse (nmlv.uNewState = LVIS_SELECTED) OrElse (nmlv.uNewState = LVIS_SELECTED_FOCUSED) Then
                If m_cancel Then
                    m.Result = New IntPtr(1)
                    m_cancel = False
                End If
            End If
        End If
    End Sub

End Class
Public Class ItemChangingEventArgs
    Inherits CancelEventArgs
    Private m_index As Integer
    Private m_item As ListViewItem
    Public Sub New(ByVal index As Integer, ByVal item As ListViewItem)
        m_index = index
        m_item = item
    End Sub
    Public ReadOnly Property Index() As Integer
        Get
            Return m_index
        End Get
    End Property
    Public ReadOnly Property Item() As ListViewItem
        Get
            Return m_item
        End Get
    End Property

End Class